/**
 *******************************************************************************
 * \brief   CAS EBX Project Work "Kaffeemaschine"
 *
 * \file    monitoring.c
 * \version 1.0
 * \date    30.06.2010
 * \author  Baehler Thomas, Liechti Beat, Sauter Marc
 * \author  Vuksic Valentina, Zbinden Rene
 *
 * \remark  Last Modifications:
 * \remark  V1.0, 30.06.2010   Initial release
 *******************************************************************************
 **/

/*
 *******************************************************************************
 * Definitions
 *******************************************************************************
 */
/** \brief The minimum amount of beans needed for a coffee */
#define BEAN_MIN 10
/** \brief The minimum amount of water needed for a coffee */
#define WATER_MIN 10
/** \brief The maximum allowed milk temperature value */
#define MILK_TEMP_MAX 8
/** \brief The minimum allowed milk temperature value */
#define MILK_TEMP_MIN 5
/** \brief The maximum allowed milk acid value */
#define MILK_ACID_MAX 8
/** \brief The minimum allowed milk acid value */
#define MILK_ACID_MIN 6
/** \brief The maximum allowed drain container value */
#define DRAIN_CONTAINER_MAX 5


/*
 *******************************************************************************
 * Imports
 *******************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>

#include "coffee2.h"
#include "channel.h"
#include "pool.h"


/*
 *******************************************************************************
 * Local Variables
 *******************************************************************************
 */
static tChannel *c18, *c19, *c20, *c21, *c22, *c23;
static tPool *p2, *p3;
static int milkCoolingOn = 1;
static int milkCoolingOff = 0;
static int timeExpired;


/*
 *******************************************************************************
 * Local Function Declaration
 *******************************************************************************
 */
static void sigtermHandler(int signal);
static void setTimeExpired(int signal);


/**
 *******************************************************************************
 * sigtermHandler
 *
 * \brief handle SIGTERM signal, close all pools and channels and exit
 *
 *******************************************************************************
 **/
static void sigtermHandler(int signal) {
	syslog(LOG_INFO, "SIGTERM reveiced, stopping ...");
	/*turn cooling off*/
	syslog(LOG_INFO, "turning milk cooling actor off");
	writeChannel(c21, &milkCoolingOff);
	/* close channels and pools */
	closeChannel(c18);
	closeChannel(c19);
	closeChannel(c20);
	closeChannel(c21);
	closeChannel(c22);
	closeChannel(c23);
	closePool(p2);
	closePool(p3);
	/* close syslog */
	closelog();
	/* close and remove the runfile */
	exit(EXIT_SUCCESS);
}


/**
 *******************************************************************************
 * setTimeExpired
 *
 * \brief handle SIGALRM signal, set timeExpired
 *
 *******************************************************************************
 **/
static void setTimeExpired(int signal) {
	timeExpired = 1;
	return;
}


/**
 *******************************************************************************
 * mainMonitoring
 *
 * \brief Activity: "Betriebsmittel Ueberwachung"
 *
 * \return pid
 *
 *******************************************************************************
 **/
pid_t mainMonitoring(){
	pid_t pid;
	sigset_t sigmask;
	struct sigaction sigtermAction, defaultAction;
	int beanSensor, waterSensor, milkTempSensor, milkAcidSensor, drainContainerSensor;
	int error, parameter;
	int oldParameter = -1;

	pid = fork();
	if (pid == 0) {
		/* syslog */
		closelog();
		openlog("coffee-monitoring", LOG_PID, LOG_DAEMON);
		/* block all signals other than SIGTERM */
		sigemptyset(&sigmask);
		sigaddset(&sigmask, SIGTERM);
		sigtermAction.sa_handler = sigtermHandler;
		sigtermAction.sa_mask = sigmask;
		if (sigaction(SIGTERM, &sigtermAction, &defaultAction) == -1){
			syslog(LOG_ERR, "unable to setup signal handling!");;
		}
		/* register alarm function */
		if (signal(SIGALRM, setTimeExpired) == SIG_ERR) {
			syslog(LOG_ERR, "can't register SIGALRM!");
		}
		/* open channels and pools */
		c18 = openChannelRead("C18", sizeof(int));  /* read from "Bohnenmenge"*/
		c19 = openChannelRead("C19", sizeof(int));  /* read from
														"Wassermenge" */
		c20 = openChannelRead("C20", sizeof(int));  /* read from
														"Milchtemperatur" */
		c21 = openChannelWrite("C21", sizeof(int)); /* write to
														"Milchkuehlung" */
		c22 = openChannelRead("C22", sizeof(int));  /* read from
														"Milchsaeure" */
		c23 = openChannelRead("C23", sizeof(int));  /* read from
														"Auffangbehaelter" */
		p2 = openPool("P2", sizeof(parameter)); 	/* "Parameter" */
		p3 = openPool("P3", sizeof(error)); 		/* "Error" */
		syslog(LOG_INFO, "activate milk cooling");
		writeChannel(c21,&milkCoolingOn);
		while (1) {
			/*
			 * Here we would implement the activity that
			 * reads the parameters and sets the sensor thresholds
			 * for the maximum and minimum operating values accordingly.
			 * For now this values are defined above.
			 * To test basic functionality the activity just logs parameter
			 * value changes
			 */
			alarm(WAIT_FOR_PARAMETERS_TIMEOUT);
			while (readFromPool(p2, &parameter) <= 0 && timeExpired == 0) {
				usleep(500);
			}
			alarm(0);
			if (timeExpired == 1) {
				syslog(LOG_ERR, "parameters could not be loaded");
				error = PARAMETER_LOAD_TIMEOUT;
				/* parameter cloud not be read */
				writeToPool(p3, &error);
			}
			else {
				if (parameter != oldParameter) {
					oldParameter = parameter;
					syslog(LOG_INFO, "loading parameters");
					/* logging defined sensor thresholds for simpler testing */
					syslog(LOG_INFO, "bean min value: %d", BEAN_MIN);
					syslog(LOG_INFO, "water min value: %d", WATER_MIN);
					syslog(LOG_INFO, "milk temperature min value: %d", MILK_TEMP_MIN);
					syslog(LOG_INFO, "milk temperature max value: %d", MILK_TEMP_MAX);
					syslog(LOG_INFO, "milk acid min value: %d", MILK_ACID_MIN);
					syslog(LOG_INFO, "milk acid max value: %d", MILK_ACID_MAX);
					syslog(LOG_INFO, "drain container full value: %d", DRAIN_CONTAINER_MAX);
				}
			}
			if (readChannel(c18, &beanSensor) > 0) {
				syslog(LOG_INFO, "read bean value: %d", beanSensor);
				if (beanSensor < BEAN_MIN){
					syslog(LOG_INFO, "sensor detected bean value low");
					error = BEAN_LOW;
					writeToPool(p3, &error);
				}
			}
			if (readChannel(c19, &waterSensor) > 0) {
				syslog(LOG_INFO, "read water value: %d", waterSensor);
				if (waterSensor < WATER_MIN){
					syslog(LOG_INFO, "sensor detected water value low");
					error = WATER_LOW;
					writeToPool(p3, &error);
				}
			}
			if (readChannel(c20, &milkTempSensor) > 0) {
				syslog(LOG_INFO, "read milk temparature value: %d",
						milkTempSensor);
				if (milkTempSensor < MILK_TEMP_MIN){
					syslog(LOG_INFO, "sensor detected milk temperature low");
					error = MILK_TEMP_LOW;
					writeToPool(p3, &error);
				}
				if (milkTempSensor > MILK_TEMP_MAX){
					syslog(LOG_INFO, "sensor detected milk temperature high");
					error = MILK_TEMP_HIGH;
					writeToPool(p3, &error);
				}
			}
			if (readChannel(c22, &milkAcidSensor) > 0) {
				syslog(LOG_INFO, "read milk acid value: %d", milkAcidSensor);
				if (milkAcidSensor < MILK_ACID_MIN){
					syslog(LOG_INFO, "sensor detected milk acid low");
					error = MILK_ACID_LOW;
					writeToPool(p3, &error);
				}
				if (milkAcidSensor > MILK_ACID_MAX){
					syslog(LOG_INFO, "sensor detected milk acid high");
					error = MILK_ACID_HIGH;
					writeToPool(p3, &error);
				}
			}
			if (readChannel(c23, &drainContainerSensor) > 0) {
				syslog(LOG_INFO, "read drain container value: %d",
						drainContainerSensor);
				if (drainContainerSensor > DRAIN_CONTAINER_MAX){
					syslog(LOG_INFO, "drain container full");
					error = DRAIN_CONTAINER_HIGH;
					writeToPool(p3, &error);
				}
			}
			usleep(500);
		}
	}
	return pid;
}
